package cn.com.zero.common.message.dubbo;

import cn.com.zero.api.message.dubbo.IMessageService;
import cn.com.zero.base.constant.ZeroConstants;
import cn.com.zero.base.service.BaseService;
import cn.com.zero.common.message.adapter.ISendMessage;
import cn.com.zero.common.message.cache.MessageCacheRedis;
import cn.com.zero.common.message.enums.MessageChannelEnum;
import cn.com.zero.common.message.mapper.IMessageMapper;
import cn.com.zero.common.message.po.MessageTypePO;
import cn.com.zero.common.message.po.VerificationCodeConfigPO;
import cn.com.zero.common.message.util.SendMessageUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;

/**
 * @author xiongxj
 * @version 1.0.0
 * @Description 消息service实现类
 * @createTime 2023/2/13 17:33
 */
@Component
@DubboService
public class MessageServiceDubbo extends BaseService implements IMessageService {
    private IMessageMapper messageMapper;
    private ISendMessage sendMessage;
    private MessageCacheRedis messageCache;
    private SendMessageUtil sendMessageUtil;

    @Override
    @Async
    public void sendMessage(String phoneNumber, String messageType, String ip, Object... args) {
        Assert.notNull(phoneNumber, "发送消息时手机号码不允许为空");
        Assert.notNull(messageType, "发送消息时消息类型不允许为空");
        Assert.notNull(ip, "发送消息时IP地址不允许为空");
        try {
            // 验证 消息类型是否存在
            MessageTypePO messageTypePO = messageMapper.queryMessageType(messageType);
            if (null == messageTypePO) {
                logger.warn("向手机号[{}]发送类型为[{}]消息时，未找到对应的消息类型", phoneNumber, messageType);
                return;
            }

            // 验证当前是否可以发送消息
            boolean is_sendMessage = sendMessageUtil.checkSendMessage(phoneNumber, messageType, ip, null);
            if (!is_sendMessage) {
                logger.warn("向[{}]手机号发送类型为[{}]消息时被拦截，当前请求的ip地址：{}", phoneNumber, messageType, ip);
                return;
            }

            // 发送消息
            sendMessage.sendMessage(phoneNumber, messageType, messageTypePO.getMessage(), args);
            // 记录发送消息记录
            if (sendMessageUtil.getMessageProperties().getChannel().equalsIgnoreCase(MessageChannelEnum.TEST.getType())) {
                // 若是测试通道，则将具体消息缓存至redis
                String message = StrUtil.format(messageTypePO.getMessage(), args);
                messageCache.saveMessage(phoneNumber, messageType, message);
            }
            messageCache.recordSendMessage(ip, phoneNumber);
        } catch (Exception e) {
            logger.warn("向手机号[{}]发送类型为[{}]的消息时，发生未知异常", phoneNumber, messageType, e);
        }
    }

    @Override
    @Async
    public void sendVerificationCode(String phoneNumber, String messageType, String ip) {
        Assert.notNull(phoneNumber, "发送验证码时手机号码不允许为空");
        Assert.notNull(messageType, "发送验证码时验证码类型不允许为空");
        Assert.notNull(ip, "发送验证码时IP地址不允许为空");

        try {
            // 验证 验证码消息类型是否存在
            VerificationCodeConfigPO codeConfig = messageMapper.queryCodeConfigByType(messageType);
            if (null == codeConfig) {
                logger.warn("向手机号[{}]发送类型为[{}]验证码时，未找到对应的验证码配置信息", phoneNumber, messageType);
                return;
            }

            // 验证当前是否可以发送验证码
            boolean is_sendMessage = sendMessageUtil.checkSendMessage(phoneNumber, messageType, ip, codeConfig.getRepeat_send_time());
            if (!is_sendMessage) {
                logger.warn("[{}]手机号发送[{}]类型的验证码时被拦截，当前请求的ip地址：{}", phoneNumber, messageType, ip);
                return;
            }

            // 生成验证码
            String verificationCode = sendMessageUtil.generateVerificationCode(codeConfig.getCode_length());
            // 发送验证码
            sendMessage.sendMessage(phoneNumber, messageType, codeConfig.getMessage(), verificationCode);
            // 保存验证码
            messageCache.saveVerificationCode(phoneNumber, messageType, verificationCode, codeConfig.getExpired_time());
            // 记录发送消息记录
            if (sendMessageUtil.getMessageProperties().getChannel().equalsIgnoreCase(MessageChannelEnum.TEST.getType())) {
                // 若是测试通道，则将具体消息缓存至redis
                String message = StrUtil.format(codeConfig.getMessage(), verificationCode);
                messageCache.saveMessage(phoneNumber, messageType, message);
            }
            messageCache.recordSendMessage(ip, phoneNumber);
        } catch (Exception e) {
            logger.warn("向手机号[{}]发送类型为[{}]验证码时，发生未知异常", phoneNumber, messageType, e);
        }
    }

    @Override
    public Long checkVerificationCode(String phoneNumber, String messageType, String verifyCode) {
        Assert.notNull(phoneNumber, "手机号码不允许为空");
        Assert.notNull(messageType, "验证码类型不允许为空");
        Assert.notNull(verifyCode, "验证码不允许为空");

        // 获取内存中验证码
        String verificationCodeMemory = messageCache.getVerificationCode(phoneNumber, messageType);
        if (null == verificationCodeMemory) {
            // 验证码已失效
            return -80000L;
        }
        if (!verifyCode.equals(verificationCodeMemory)) {
            // 验证码不正确
            return -80001L;
        }
        // 验证通过后需要移除验证码
        messageCache.removeVerificationCode(phoneNumber, messageType);
        return ZeroConstants.RETURN_CODE_SUCCESS;
    }

    @Autowired
    public void setMessageMapper(IMessageMapper messageMapper) {
        this.messageMapper = messageMapper;
    }

    @Resource
    public void setSendMessage(ISendMessage sendMessage) {
        this.sendMessage = sendMessage;
    }

    @Autowired
    public void setMessageCache(MessageCacheRedis messageCache) {
        this.messageCache = messageCache;
    }

    @Autowired
    public void setSendMessageUtil(SendMessageUtil sendMessageUtil) {
        this.sendMessageUtil = sendMessageUtil;
    }
}
